home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / telecomm / sticpsrc.lzh / SOURCE.ARC / IPROUTE.C < prev    next >
C/C++ Source or Header  |  1990-03-13  |  12KB  |  447 lines

  1. /* Lower half of IP, consisting of gateway routines
  2.  * Includes routing and options processing code
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "internet.h"
  7. #include "timer.h"
  8. #include "netuser.h"
  9. #include "ip.h"
  10. #include "icmp.h"
  11. #include "iface.h"
  12. #include "trace.h"
  13.  
  14. struct route *routes[33][NROUTE];    /* Routing table */
  15.  
  16. int32 ip_addr;
  17. struct ip_stats ip_stats;
  18.  
  19. #ifndef GWONLY
  20. struct mbuf *loopq;    /* Queue for loopback packets */
  21. #endif
  22.  
  23. /* Route an IP datagram. This is the "hopper" through which all IP datagrams,
  24.  * coming or going, must pass.
  25.  *
  26.  * "rxbroadcast" is set to indicate that the packet came in on a subnet
  27.  * broadcast. The router will kick the packet upstairs regardless of the
  28.  * IP destination address.
  29.  */
  30. int
  31. ip_route(bp,rxbroadcast)
  32. struct mbuf *bp;
  33. char rxbroadcast;    /* True if packet had link broadcast address */
  34. {
  35.     struct mbuf *htonip();
  36.     void ip_recv();
  37.     struct ip ip;            /* IP header being processed */
  38.     int16 ip_len;            /* IP header length */
  39.     int16 length;            /* Length of data portion */
  40.     int32 gateway;            /* Gateway IP address */
  41.     register struct route *rp;    /* Route table entry */
  42.     struct interface *iface;    /* Output interface, possibly forwarded */
  43.     struct route *rt_lookup();
  44.     int16 offset;            /* Offset into current fragment */
  45.     int16 mf_flag;            /* Original datagram MF flag */
  46.     int strict = 0;            /* Strict source routing flag */
  47.     char precedence;        /* Extracted from tos field */
  48.     char delay;
  49.     char throughput;
  50.     char reliability;
  51.     int16 opt_len;        /* Length of current option */
  52.     char *opt;        /* -> beginning of current option */
  53.     char *ptr;        /* -> pointer field in source route fields */
  54.     struct mbuf *tbp;
  55.  
  56.     ip_stats.total++;
  57.     if(len_mbuf(bp) < IPLEN){
  58.         /* The packet is shorter than a legal IP header */
  59.         ip_stats.runt++;
  60.         free_p(bp);
  61.         return -1;
  62.     }
  63.     /* Sneak a peek at the IP header's IHL field to find its length */
  64.     ip_len = (bp->data[0] & 0xf) << 2;
  65.     if(ip_len < IPLEN){
  66.         /* The IP header length field is too small */
  67.         ip_stats.length++;
  68.         free_p(bp);
  69.         return -1;
  70.     }
  71.     if(cksum(NULLHEADER,bp,ip_len) != 0){
  72.         /* Bad IP header checksum; discard */
  73.         ip_stats.checksum++;
  74.         free_p(bp);
  75.         return -1;
  76.     }
  77.     /* Extract IP header */
  78.     ntohip(&ip,&bp);
  79.  
  80.     if(ip.version != IPVERSION){
  81.         /* We can't handle this version of IP */
  82.         ip_stats.version++;
  83.         free_p(bp);
  84.         return -1;
  85.     }
  86.     /* Trim data segment if necessary. */
  87.     length = ip.length - ip_len;    /* Length of data portion */
  88.     trim_mbuf(&bp,length);
  89.  
  90.     /* Process options, if any. Also compute length of secondary IP
  91.      * header in case fragmentation is needed later
  92.      */
  93.     strict = 0;
  94.     for(opt = ip.options; opt < &ip.options[ip.optlen];opt += opt_len){
  95.         /* Most options have a length field. If this is a EOL or NOOP,
  96.          * this (garbage) value won't be used
  97.          */
  98.         opt_len = uchar(opt[1]);
  99.  
  100.         switch(opt[0] & OPT_NUMBER){
  101.         case IP_EOL:
  102.             goto no_opt;    /* End of options list, we're done */
  103.         case IP_NOOP:
  104.             opt_len = 1;
  105.             break;        /* No operation, skip to next option */
  106.         case IP_SSROUTE:    /* Strict source route & record route */
  107.             strict = 1;    /* note fall-thru */
  108.         case IP_LSROUTE:    /* Loose source route & record route */
  109.             /* Source routes are ignored unless we're in the
  110.              * destination field
  111.              */
  112.             if(ip.dest != ip_addr)
  113.                 break;    /* Skip to next option */
  114.             if(uchar(opt[2]) >= opt_len){
  115.                 break;    /* Route exhausted; it's for us */
  116.             }
  117.             /* Put address for next hop into destination field,
  118.              * put our address into the route field, and bump
  119.              * the pointer
  120.              */
  121.             ptr = opt + uchar(opt[2]) - 1;
  122.             ip.dest = get32(ptr);
  123.             put32(ptr,ip_addr);
  124.             opt[2] += 4;
  125.             break;
  126.         case IP_RROUTE: /* Record route */
  127.             if(uchar(opt[2]) >= opt_len){
  128.                 /* Route area exhausted; kick back an error */
  129.                 union icmp_args icmp_args;
  130.  
  131.                 icmp_args.pointer = IPLEN + opt - ip.options;
  132.                 icmp_output(&ip,bp,PARAM_PROB,0,&icmp_args);
  133.                 free_p(bp);
  134.                 return -1;
  135.             }
  136.             /* Add our address to the route */
  137.             ptr = opt + uchar(opt[2]) - 1;
  138.             ptr = put32(ptr,ip_addr);
  139.             opt[2] += 4;
  140.             break;
  141.         }
  142.     }
  143. no_opt:
  144.  
  145.     /* See if it's a broadcast or addressed to us, and kick it upstairs */
  146.     if(ip.dest == ip_addr || rxbroadcast){
  147. #ifdef    GWONLY
  148.     /* We're only a gateway, we have no host level protocols */
  149.         if(!rxbroadcast)
  150.             icmp_output(&ip,bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)NULL);
  151.         free_p(bp);
  152. #else
  153.  
  154.         /* If this is a local loopback packet, place on the loopback
  155.          * queue for processing in the main loop. This prevents the
  156.          * infinite stack recursion and other problems that would
  157.          * otherwise occur when we talk to ourselves, e.g., with ftp
  158.          */
  159.         if(ip.source == ip_addr){
  160.             /* Put IP header back on */
  161.             if((tbp = htonip(&ip,bp)) == NULLBUF){
  162.                 free_p(bp);
  163.                 return -1;
  164.             }
  165.             /* Copy loopback packet into new buffer.
  166.              * This avoids an obscure problem with TCP which
  167.              * dups its outgoing data before transmission and
  168.              * then frees it when an ack comes, even though the
  169.              * receiver might not have actually read it yet
  170.              */
  171.             bp = copy_p(tbp,len_mbuf(tbp));
  172.             free_p(tbp);
  173.             if(bp == NULLBUF)
  174.                 return -1;
  175.             enqueue(&loopq,bp);
  176.         } else {
  177.             ip_recv(&ip,bp,rxbroadcast);
  178.         }
  179. #endif
  180.         return 0;
  181.     }
  182.  
  183.     /* Decrement TTL and discard if zero */
  184.     if(--ip.ttl == 0){
  185.         /* Send ICMP "Time Exceeded" message */
  186.         icmp_output(&ip,bp,TIME_EXCEED,0,NULLICMP);
  187.         free_p(bp);
  188.         return -1;
  189.     }
  190.     /* Look up target address in routing table */
  191.     if((rp = rt_lookup(ip.dest)) == NULLROUTE){
  192.         /* No route exists, return unreachable message */
  193.         icmp_output(&ip,bp,DEST_UNREACH,HOST_UNREACH,NULLICMP);
  194.         free_p(bp);
  195.         return -1;
  196.     }
  197.     /* Check for output forwarding and divert if necessary */
  198.     iface = rp->interface;
  199.     if(iface->forw != NULLIF)
  200.         iface = iface->forw;
  201.  
  202.     /* Find gateway; zero gateway in routing table means "send direct" */
  203.     if(rp->gateway == (int32)0)
  204.         gateway = ip.dest;
  205.     else
  206.         gateway = rp->gateway;
  207.  
  208.     if(strict && gateway != ip.dest){
  209.         /* Strict source routing requires a direct entry */
  210.         icmp_output(&ip,bp,DEST_UNREACH,ROUTE_FAIL,NULLICMP);
  211.         free_p(bp);
  212.         return -1;
  213.     }
  214.     precedence = PREC(ip.tos);
  215.     delay = ip.tos & DELAY;
  216.     throughput = ip.tos & THRUPUT;
  217.     reliability = ip.tos & RELIABILITY;
  218.  
  219.     if(ip.length <= iface->mtu){
  220.         /* Datagram smaller than interface MTU; put header
  221.          * back on and send normally
  222.          */
  223.         if((tbp = htonip(&ip,bp)) == NULLBUF){
  224.             free_p(bp);
  225.             return -1;
  226.         }
  227.         return (*iface->send)(tbp,iface,gateway,
  228.             precedence,delay,throughput,reliability);
  229.     }
  230.     /* Fragmentation needed */
  231.     if(ip.fl_offs & DF){
  232.         /* Don't Fragment set; return ICMP message and drop */
  233.         icmp_output(&ip,bp,DEST_UNREACH,FRAG_NEEDED,NULLICMP);
  234.         free_p(bp);
  235.         return -1;
  236.     }
  237.     /* Create fragments */
  238.     offset = (ip.fl_offs & F_OFFSET) << 3;
  239.     mf_flag = ip.fl_offs & MF;    /* Save original MF flag */
  240.     while(length != 0){        /* As long as there's data left */
  241.         int16 fragsize;        /* Size of this fragment's data */
  242.         struct mbuf *f_data;    /* Data portion of fragment */
  243.  
  244.         /* After the first fragment, should remove those
  245.          * options that aren't supposed to be copied on fragmentation
  246.          */
  247.         ip.fl_offs = offset >> 3;
  248.         if(length + ip_len <= iface->mtu){
  249.             /* Last fragment; send all that remains */
  250.             fragsize = length;
  251.             ip.fl_offs |= mf_flag;    /* Pass original MF flag */
  252.         } else {
  253.             /* More to come, so send multiple of 8 bytes */
  254.             fragsize = (iface->mtu - ip_len) & 0xfff8;
  255.             ip.fl_offs |= MF;
  256.         }
  257.         ip.length = fragsize + ip_len;
  258.  
  259.         /* Move the data fragment into a new, separate mbuf */
  260.         if((f_data = alloc_mbuf(fragsize)) == NULLBUF){
  261.             free_p(bp);
  262.             return -1;
  263.         }
  264.         f_data->cnt = pullup(&bp,f_data->data,fragsize);
  265.  
  266.         /* Put IP header back on */
  267.         if((tbp = htonip(&ip,f_data)) == NULLBUF){
  268.             free_p(f_data);
  269.             free_p(bp);
  270.             return -1;
  271.         }
  272.         /* and ship it out */
  273.         if((*iface->send)(tbp,iface,gateway,
  274.             precedence,delay,throughput,reliability) == -1)
  275.             return -1;
  276.  
  277.         offset += fragsize;
  278.         length -= fragsize;
  279.     }
  280.     return 0;
  281. }
  282.  
  283. /* C